<?php

class Domain implements IDomainDefinition
{

  protected static $instance;

  protected $definitions = array();

  /**
   *
   * @return IDomainDefinition
   */
  public static function getInstance()
  {
    if (empty(Domain::$instance)) {
      Domain::$instance = new Domain();
    }

    return Domain::$instance;
  }

  public function getRepository($name)
  {
    if (! $this->hasDefinition('repository', $name)) {
      throw new DomainException("Repository not found: <b>$name</b>");
    }

    return $this->getDefinition('repository', $name);
  }

  /**
   *
   * @return void
   */
  private function __construct()
  {
  }

  public function addDefinition($type, $name, array $def)
  {
    if ($this->hasDefinition($type, $name)) {
      throw new DomainException("Duplicate domain object definition: <b>$name</b>");
    }

    $this->definitions[$type][$name] = $def;
  }

  public function hasDefinition($type, $name)
  {
    return isset($this->definitions[$type][$name]);
  }

  public function getDefinition($type, $name)
  {
    if (! $this->hasDefinition($type, $name)) {
      throw new DomainException("Domain object definition not found: <b>$name</b>");
    }

    return $this->definitions[$type][$name];
  }

  public function factoryObject($type, $name)
  {
    $def = $this->getDefinition($type, $name);

    $class = isset($def['connections']) ? 'AggregateDefinition' : 'EntityDefinition';

    $this->addObject($name, new $class($name, $def));
  }

  /**
   * (non-PHPdoc)
   * @see simplify/kernel/domain/api/IDomainDefinition#addObject($name, $def)
   */
  public function addObject($name, IDomObjDefinition $def)
  {
    $this->definitions['object'][$name] = & $def;
  }

  /**
   * (non-PHPdoc)
   * @see simplify/kernel/domain/api/IDomainDefinition#getObject($name)
   */
  public function getObject($name)
  {
    if (! $this->hasObject($name)) {
      $this->factoryObject('object', $name);
    }

    return $this->definitions['object'][$name];
  }

  /**
   * (non-PHPdoc)
   * @see simplify/kernel/domain/api/IDomainDefinition#getObjects()
   */
  public function getObjects()
  {
    foreach ($this->definitions['object'] as $name => $def) {
      if (! $this->hasObject($name)) {
        $this->factoryObject('object', $name);
      }
    }

    return $this->definitions['object'];
  }

  /**
   * (non-PHPdoc)
   * @see simplify/kernel/domain/api/IDomainDefinition#hasObject($name)
   */
  public function hasObject($name)
  {
    return (isset($this->definitions['object'][$name]) && $this->definitions['object'][$name] instanceof IDomObjDefinition);
  }

  /**
   *
   * @param $def
   * @return IEntityDefinition
   */
  public static function toEntity($def)
  {
    if (! $def instanceof IEntityDefinition) {
      throw new DomainTypeConversionException("Could not convert to IEntityDefinition");
    }

    return $def;
  }

  /**
   *
   * @param $def
   * @return IAggregateDefinition
   */
  public static function toAggregate($def)
  {
    if (! is_a($def, 'IAggregateDefinition')) {
      throw new DomainTypeConversionException("Could not convert to IAggregateDefinition");
    }

    return $def;
  }

}

?>